﻿using System;
using System.ComponentModel;
using System.Data;
using System.IO;
using System.Linq;
using org.se.fs.model;
using org.se.fs.presenter.ITask;
using org.se.fs.presenter.Library;

namespace org.se.fs.presenter.Task
{
    public class Splash : ISplash
    {
        private readonly BackgroundWorker _bgwLoadCOnfig;
        private readonly BackgroundWorker _bgwCheckConnection;
        public event FormEvent.FormEventHandler OnLoadConfig;
        public event FormEvent.FormEventHandler OnCheckConnection;

        public Splash()
        {
            _bgwLoadCOnfig = new BackgroundWorker();
            _bgwLoadCOnfig.DoWork += BgwLoadDoWork;
            _bgwLoadCOnfig.RunWorkerCompleted += BgwLoadRunWorkerCompleted;

            _bgwCheckConnection = new BackgroundWorker();
            _bgwCheckConnection.DoWork += BgwCheckConnectionDoWork;
            _bgwCheckConnection.RunWorkerCompleted += BgwCheckConnectionRunWorkerCompleted;
        }

        static void BgwCheckConnectionDoWork(object sender, DoWorkEventArgs e)
        {
            e.Result = new Validator().TestConnection(DataContext.ConnectionString);
        }

        void BgwCheckConnectionRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            var isConnected = (bool)e.Result;
            OnCheckConnection(this,
                                      new FormEvent(isConnected)
                                      {
                                          Exception =
                                              isConnected ? null : new Exception("Could not connect to database.")
                                      });
        }

        static void BgwLoadDoWork(object sender, DoWorkEventArgs e)
        {
            if (!File.Exists(Config.FileName))
            {
                e.Result = new Exception(string.Format("Filename {0} does not exist.", Config.FileName));
                return;
            }

            string xml;

            using (var sr = new StreamReader(Config.FileName))
                xml = sr.ReadToEnd();

            try
            {
                xml = Cryptography.Decrypt(xml, Config.PassPhrase, Config.SaltValue, Config.HashAlgorithm,
                                           Config.PasswordIterations, Config.InitVector, Config.KeySize);
            }
            catch (Exception ex)
            {
                e.Result = ex;
                return;
            }

            EnumerableRowCollection<string> providerType;
            using (var dsDataSet = new DataSet())
            {
                using (var sr = new StringReader(xml))
                    dsDataSet.ReadXml(sr);

                if (dsDataSet.Tables[0].Rows.Count.Equals(0))
                {
                    e.Result = new Exception("Does not contain any valid config.");
                    return;
                }

                #region Config - ConnectionString
                var connectionString =
                    (dsDataSet.Tables[0].AsEnumerable().Where(a => a.Field<string>("NAME") == "ConnectionString").Select(
                        a => a.Field<string>("VALUE")));
                if (connectionString.Count().Equals(0))
                {
                    e.Result = new Exception("Could not find config ConnectionString.");
                    return;
                }
                DataContext.ConnectionString = connectionString.First();


                providerType = (dsDataSet.Tables[0].AsEnumerable().Where(a => a.Field<string>("NAME") == "ProviderType").Select(a => a.Field<string>("VALUE")));
            }
            if (providerType.Count().Equals(0))
            {
                e.Result = new Exception("Could not find config ProviderType.");
                return;
            }

            DataContext.ProviderType = (ProviderType)Enum.Parse(typeof(ProviderType), providerType.First());
            #endregion

            e.Result = null;
        }

        void BgwLoadRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            var exception = e.Result == null ? null : (Exception)e.Result;
            OnLoadConfig(this, new FormEvent(exception == null) { Exception = exception });
        }

        public void LoadConfig()
        {
            _bgwLoadCOnfig.RunWorkerAsync();
        }

        public void CheckConnection()
        {
            _bgwCheckConnection.RunWorkerAsync();
        }
    }
}
